home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gxclpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  41.0 KB  |  1,390 lines

  1. /* Copyright (C) 1995, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gxclpath.c,v 1.8 2000/09/19 19:00:35 lpd Exp $ */
  20. /* Higher-level path operations for band lists */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gpcheck.h"
  25. #include "gserrors.h"
  26. #include "gxdevice.h"
  27. #include "gxdevmem.h"        /* must precede gxcldev.h */
  28. #include "gxcldev.h"
  29. #include "gxclpath.h"
  30. #include "gxcolor2.h"
  31. #include "gxdcolor.h"
  32. #include "gxpaint.h"        /* for gx_fill/stroke_params */
  33. #include "gzpath.h"
  34. #include "gzcpath.h"
  35. #include "stream.h"
  36.  
  37. #ifdef E
  38. #undef E
  39. #endif
  40.  
  41. /* Statistics */
  42. #ifdef DEBUG
  43. ulong stats_cmd_diffs[5];
  44. #endif
  45.  
  46. /* Forward declarations */
  47. private int cmd_put_path(P8(gx_device_clist_writer * cldev,
  48.                 gx_clist_state * pcls, const gx_path * ppath,
  49.                 fixed ymin, fixed ymax, byte op,
  50.                 bool implicit_close, segment_notes keep_notes));
  51.  
  52. /* ------ Utilities ------ */
  53.  
  54. /* Compute the colors used by a colored halftone. */
  55. private gx_color_index
  56. colored_halftone_colors_used(gx_device_clist_writer *cldev,
  57.                  const gx_drawing_color *pdcolor)
  58. {
  59.     /*
  60.      * We only know how to compute an accurate color set for the
  61.      * standard CMYK color mapping function.
  62.      */
  63.     if (dev_proc(cldev, map_cmyk_color) != cmyk_1bit_map_cmyk_color)
  64.     return ((gx_color_index)1 << cldev->color_info.depth) - 1;
  65.     /*
  66.      * Note that c_base[0], and the low-order bit of plane_mask,
  67.      * correspond to cyan: this requires reversing the bit order of
  68.      * the plane mask.
  69.      */
  70.     return
  71.     ((pdcolor->colors.colored.c_base[0] << 3) |
  72.      (pdcolor->colors.colored.c_base[1] << 2) |
  73.      (pdcolor->colors.colored.c_base[2] << 1) |
  74.      (pdcolor->colors.colored.c_base[3]) |
  75.      (byte_reverse_bits[pdcolor->colors.colored.plane_mask] >> 4));
  76. }
  77.  
  78. /*
  79.  * Compute whether a drawing operation will require the slow (full-pixel)
  80.  * RasterOp implementation.  If pdcolor is not NULL, it is the texture for
  81.  * the RasterOp.
  82.  */
  83. bool
  84. cmd_slow_rop(gx_device *dev, gs_logical_operation_t lop,
  85.     const gx_drawing_color *pdcolor)
  86. {
  87.     gs_rop3_t rop = lop_rop(lop);
  88.  
  89.     if (pdcolor != 0 && gx_dc_is_pure(pdcolor)) {
  90.     gx_color_index color = gx_dc_pure_color(pdcolor);
  91.  
  92.     if (color == gx_device_black(dev))
  93.         rop = rop3_know_T_0(rop);
  94.     else if (color == gx_device_white(dev))
  95.         rop = rop3_know_T_1(rop);
  96.     }
  97.     return !(rop == rop3_0 || rop == rop3_1 ||
  98.          rop == rop3_D || rop == rop3_S || rop == rop3_T);
  99. }
  100.  
  101. /* Write out the color for filling, stroking, or masking. */
  102. /* We should be able to share this with clist_tile_rectangle, */
  103. /* but I don't see how to do it without adding a level of procedure. */
  104. int
  105. cmd_put_drawing_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
  106.               const gx_drawing_color * pdcolor)
  107. {
  108.     ulong offset_temp;
  109.     int type;
  110.  
  111.     if (gx_dc_is_pure(pdcolor)) {
  112.     gx_color_index color1 = gx_dc_pure_color(pdcolor);
  113.  
  114.     pcls->colors_used.or |= color1;
  115.     if (color1 != pcls->colors[1]) {
  116.         int code = cmd_set_color1(cldev, pcls, color1);
  117.  
  118.         if (code < 0)
  119.         return code;
  120.     }
  121.     return cmd_dc_type_pure;
  122.     }
  123.     if (gx_dc_is_binary_halftone(pdcolor)) {
  124.     const gx_strip_bitmap *tile = gx_dc_binary_tile(pdcolor);
  125.     gx_color_index color0 = gx_dc_binary_color0(pdcolor);
  126.     gx_color_index color1 = gx_dc_binary_color1(pdcolor);
  127.     int code;
  128.  
  129.     pcls->colors_used.or |= color0 | color1;
  130.     /* Set up tile and colors as for clist_tile_rectangle. */
  131.     if (!cls_has_tile_id(cldev, pcls, tile->id, offset_temp)) {
  132.         int depth =
  133.         (color1 == gx_no_color_index &&
  134.          color0 == gx_no_color_index ?
  135.          cldev->color_info.depth : 1);
  136.  
  137.         if (tile->id == gx_no_bitmap_id)
  138.         return_error(-1);    /* can't cache tile */
  139.         if ((code = clist_change_tile(cldev, pcls, tile, depth)) < 0)
  140.         return code;
  141.     }
  142.     if (color1 != pcls->tile_colors[1] ||
  143.         color0 != pcls->tile_colors[0]
  144.         ) {
  145.         if ((code = cmd_set_tile_colors(cldev, pcls, color0, color1)) < 0)
  146.         return code;
  147.     }
  148.     type = cmd_dc_type_ht;
  149.     } else if (gx_dc_is_colored_halftone(pdcolor)) {
  150.     const gx_device_halftone *pdht = pdcolor->colors.colored.c_ht;
  151.     int num_comp = pdht->num_comp;
  152.     byte buf[4 + 4 * cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))];
  153.     byte *bp = buf;
  154.     int i;
  155.     byte cmd;
  156.     uint short_bases = 0;
  157.     ulong bases = 0;
  158.     byte flags = 0;
  159.     byte *dp;
  160.     int code;
  161.  
  162.     pcls->colors_used.or |=
  163.         colored_halftone_colors_used(cldev, pdcolor);
  164.     /****** HOW TO TELL IF COLOR IS ALREADY SET? ******/
  165.     if (pdht->id != cldev->device_halftone_id) {
  166.         int code = cmd_put_halftone(cldev, pdht, pdht->type);
  167.  
  168.         if (code < 0)
  169.         return code;
  170.         cldev->device_halftone_id = pdht->id;
  171.     }
  172.     for (i = 0; i < num_comp; ++i) {
  173.         uint base = pdcolor->colors.colored.c_base[i];
  174.  
  175.         if (base > 31)
  176.         return_error(gs_error_rangecheck);
  177.         bases |= base << ((3 - i) * 5);
  178.         short_bases |= base << (3 - i);
  179.         if (pdcolor->colors.colored.c_level[i])
  180.         flags |= 0x80 >> i;
  181.     }
  182.     if (bases & 0xf7bde) {
  183.         /* Some base value requires more than 1 bit. */
  184.         cmd = cmd_opv_set_color;
  185.         *bp++ = flags | (byte)(bases >> 16);
  186.         *bp++ = (byte) (bases >> 8);
  187.         *bp++ = (byte) bases;
  188.     } else {
  189.         /* The bases all fit in 1 bit each. */
  190.         cmd = cmd_opv_set_color_short;
  191.         *bp++ = flags | (byte)short_bases;
  192.     }
  193.     for (i = 0; i < num_comp; ++i)
  194.         if (flags & (0x80 >> i))
  195.         bp = cmd_put_w((uint)pdcolor->colors.colored.c_level[i], bp);
  196.     /****** IGNORE alpha ******/
  197.     code = set_cmd_put_op(dp, cldev, pcls, cmd, bp - buf + 1);
  198.     if (code < 0)
  199.         return code;
  200.     memcpy(dp + 1, buf, bp - buf);
  201.     type = cmd_dc_type_color;
  202.     } else
  203.     return_error(-1);    /* the color type was not known - unknown error */
  204.     /* Any non-pure color will require the phase. */
  205.     {
  206.     int px = pdcolor->phase.x, py = pdcolor->phase.y;
  207.  
  208.     if (px != pcls->tile_phase.x || py != pcls->tile_phase.y) {
  209.         int code = cmd_set_tile_phase(cldev, pcls, px, py);
  210.  
  211.         if (code < 0)
  212.         return code;
  213.     }
  214.     }
  215.     return type;
  216. }
  217.  
  218. /* Compute the colors used by a drawing color. */
  219. gx_color_index
  220. cmd_drawing_colors_used(gx_device_clist_writer *cldev,
  221.             const gx_drawing_color * pdcolor)
  222. {
  223.     if (gx_dc_is_pure(pdcolor))
  224.     return gx_dc_pure_color(pdcolor);
  225.     else if (gx_dc_is_binary_halftone(pdcolor))
  226.     return gx_dc_binary_color0(pdcolor) | gx_dc_binary_color1(pdcolor);
  227.     else if (gx_dc_is_colored_halftone(pdcolor))
  228.     return colored_halftone_colors_used(cldev, pdcolor);
  229.     else
  230.     return ((gx_color_index)1 << cldev->color_info.depth) - 1;
  231. }
  232.  
  233.  
  234. /* Clear (a) specific 'known' flag(s) for all bands. */
  235. /* We must do this whenever the value of a 'known' parameter changes. */
  236. void
  237. cmd_clear_known(gx_device_clist_writer * cldev, uint known)
  238. {
  239.     uint unknown = ~known;
  240.     gx_clist_state *pcls = cldev->states;
  241.     int i;
  242.  
  243.     for (i = cldev->nbands; --i >= 0; ++pcls)
  244.     pcls->known &= unknown;
  245. }
  246.  
  247. /* Check whether we need to change the clipping path in the device. */
  248. bool
  249. cmd_check_clip_path(gx_device_clist_writer * cldev, const gx_clip_path * pcpath)
  250. {
  251.     if (pcpath == NULL)
  252.     return false;
  253.     /* The clip path might have moved in memory, so even if the */
  254.     /* ids match, update the pointer. */
  255.     cldev->clip_path = pcpath;
  256.     if (pcpath->id == cldev->clip_path_id)
  257.     return false;
  258.     cldev->clip_path_id = pcpath->id;
  259.     return true;
  260. }
  261.  
  262. /*
  263.  * Check the graphics state elements that need to be up to date for filling
  264.  * or stroking.
  265.  */
  266. #define FILL_KNOWN\
  267.  (cj_ac_sa_known | flatness_known | op_bm_tk_known | opacity_alpha_known |\
  268.   shape_alpha_known | fill_adjust_known | alpha_known | clip_path_known)
  269. private void
  270. cmd_check_fill_known(gx_device_clist_writer *cdev, const gs_imager_state *pis,
  271.              floatp flatness, const gs_fixed_point *padjust,
  272.              const gx_clip_path *pcpath, uint *punknown)
  273. {
  274.     /*
  275.      * stroke_adjust is not needed for fills, and none of these are needed
  276.      * if the path has no curves, but it's easier to update them all.
  277.      */
  278.     if (state_neq(line_params.curve_join) || state_neq(accurate_curves) ||
  279.     state_neq(stroke_adjust)
  280.     ) {
  281.     *punknown |= cj_ac_sa_known;
  282.     state_update(line_params.curve_join);
  283.     state_update(accurate_curves);
  284.     state_update(stroke_adjust);
  285.     }
  286.     if (cdev->imager_state.flatness != flatness) {
  287.     *punknown |= flatness_known;
  288.     cdev->imager_state.flatness = flatness;
  289.     }
  290.     if (state_neq(overprint) || state_neq(overprint_mode) ||
  291.     state_neq(blend_mode) || state_neq(text_knockout)
  292.     ) {
  293.     *punknown |= op_bm_tk_known;
  294.     state_update(overprint);
  295.     state_update(overprint_mode);
  296.     state_update(blend_mode);
  297.     state_update(text_knockout);
  298.     }
  299.     if (state_neq(opacity.alpha)) {
  300.     *punknown |= opacity_alpha_known;
  301.     state_update(opacity.alpha);
  302.     }
  303.     if (state_neq(shape.alpha)) {
  304.     *punknown |= shape_alpha_known;
  305.     state_update(shape.alpha);
  306.     }
  307.     if (cdev->imager_state.fill_adjust.x != padjust->x ||
  308.     cdev->imager_state.fill_adjust.y != padjust->y
  309.     ) {
  310.     *punknown |= fill_adjust_known;
  311.     cdev->imager_state.fill_adjust = *padjust;
  312.     }
  313.     if (cdev->imager_state.alpha != pis->alpha) {
  314.     *punknown |= alpha_known;
  315.     state_update(alpha);
  316.     }
  317.     if (cmd_check_clip_path(cdev, pcpath))
  318.     *punknown |= clip_path_known;
  319. }
  320.  
  321. /* Write out values of any unknown parameters. */
  322. int
  323. cmd_write_unknown(gx_device_clist_writer * cldev, gx_clist_state * pcls,
  324.           uint must_know)
  325. {
  326.     uint unknown = ~pcls->known & must_know;
  327.     uint misc2_unknown = unknown & misc2_all_known;
  328.     byte *dp;
  329.     int code;
  330.  
  331.     if (misc2_unknown) {
  332.     byte buf[
  333.          1 +        /* cap_join */
  334.          1 +        /* cj_ac_sa */
  335.          sizeof(float) +    /* flatness */
  336.          sizeof(float) +    /* line width */
  337.          sizeof(float) +    /* miter limit */
  338.          1 +        /* op_bm_tk */
  339.          sizeof(float) * 2 +  /* opacity/shape alpha */
  340.          sizeof(cldev->imager_state.alpha)
  341.     ];
  342.     byte *bp = buf;
  343.  
  344.     if (unknown & cap_join_known) {
  345.         *bp++ = (cldev->imager_state.line_params.cap << 3) +
  346.         cldev->imager_state.line_params.join;
  347.     }
  348.     if (unknown & cj_ac_sa_known) {
  349.         *bp++ =
  350.         ((cldev->imager_state.line_params.curve_join + 1) << 2) +
  351.         (cldev->imager_state.accurate_curves ? 2 : 0) +
  352.         (cldev->imager_state.stroke_adjust ? 1 : 0);
  353.     }
  354.     if (unknown & flatness_known) {
  355.         memcpy(bp, &cldev->imager_state.flatness, sizeof(float));
  356.         bp += sizeof(float);
  357.     }
  358.     if (unknown & line_width_known) {
  359.         float width =
  360.         gx_current_line_width(&cldev->imager_state.line_params);
  361.  
  362.         memcpy(bp, &width, sizeof(width));
  363.         bp += sizeof(width);
  364.     }
  365.     if (unknown & miter_limit_known) {
  366.         memcpy(bp, &cldev->imager_state.line_params.miter_limit,
  367.            sizeof(float));
  368.         bp += sizeof(float);
  369.     }
  370.     if (unknown & op_bm_tk_known) {
  371.         *bp++ =
  372.         ((int)cldev->imager_state.blend_mode << 3) +
  373.         (cldev->imager_state.text_knockout << 2) +
  374.         (cldev->imager_state.overprint_mode << 1) +
  375.         cldev->imager_state.overprint;
  376.     }
  377.     if (unknown & opacity_alpha_known) {
  378.         memcpy(bp, &cldev->imager_state.opacity.alpha, sizeof(float));
  379.         bp += sizeof(float);
  380.     }
  381.     if (unknown & shape_alpha_known) {
  382.         memcpy(bp, &cldev->imager_state.shape.alpha, sizeof(float));
  383.         bp += sizeof(float);
  384.     }
  385.     if (unknown & alpha_known) {
  386.         memcpy(bp, &cldev->imager_state.alpha,
  387.            sizeof(cldev->imager_state.alpha));
  388.         bp += sizeof(cldev->imager_state.alpha);
  389.     }
  390.     code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2,
  391.                   1 + cmd_sizew(misc2_unknown) + bp - buf);
  392.     if (code < 0)
  393.         return 0;
  394.     memcpy(cmd_put_w(misc2_unknown, dp + 1), buf, bp - buf);
  395.     pcls->known |= misc2_unknown;
  396.     }
  397.     if (unknown & fill_adjust_known) {
  398.     code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_fill_adjust,
  399.                   1 + sizeof(fixed) * 2);
  400.     if (code < 0)
  401.         return code;
  402.     memcpy(dp + 1, &cldev->imager_state.fill_adjust.x, sizeof(fixed));
  403.     memcpy(dp + 1 + sizeof(fixed), &cldev->imager_state.fill_adjust.y, sizeof(fixed));
  404.     pcls->known |= fill_adjust_known;
  405.     }
  406.     if (unknown & ctm_known) {
  407.     stream s;
  408.     uint len;
  409.  
  410.     swrite_position_only(&s);
  411.     sput_matrix(&s, (const gs_matrix *)&cldev->imager_state.ctm);
  412.     len = (uint)stell(&s);
  413.     code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_ctm, len + 1);
  414.     if (code < 0)
  415.         return code;
  416.     swrite_string(&s, dp + 1, len);
  417.     sput_matrix(&s, (const gs_matrix *)&cldev->imager_state.ctm);
  418.     pcls->known |= ctm_known;
  419.     }
  420.     if (unknown & dash_known) {
  421.     int n = cldev->imager_state.line_params.dash.pattern_size;
  422.  
  423.     code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_dash,
  424.                   2 + (n + 2) * sizeof(float));
  425.     if (code < 0)
  426.         return code;
  427.     dp[1] = n + (cldev->imager_state.line_params.dash.adapt ? 0x80 : 0) +
  428.         (cldev->imager_state.line_params.dot_length_absolute ? 0x40 : 0);
  429.     memcpy(dp + 2, &cldev->imager_state.line_params.dot_length,
  430.            sizeof(float));
  431.     memcpy(dp + 2 + sizeof(float),
  432.            &cldev->imager_state.line_params.dash.offset,
  433.            sizeof(float));
  434.     if (n != 0)
  435.         memcpy(dp + 2 + sizeof(float) * 2,
  436.            cldev->dash_pattern, n * sizeof(float));
  437.     pcls->known |= dash_known;
  438.     }
  439.     if (unknown & clip_path_known) {
  440.     /*
  441.      * We can write out the clipping path either as rectangles
  442.      * or as a real (filled) path.
  443.      */
  444.     const gx_clip_path *pcpath = cldev->clip_path;
  445.     int band_height = cldev->page_band_height;
  446.     int ymin = (pcls - cldev->states) * band_height;
  447.     int ymax = min(ymin + band_height, cldev->height);
  448.     gs_fixed_rect box;
  449.     bool punt_to_outer_box = false;
  450.     int code;
  451.  
  452.     code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_begin_clip, 1);
  453.     if (code < 0)
  454.         return code;
  455.     if (pcpath->path_valid) {
  456.         if (gx_path_is_rectangle(&pcpath->path, &box) &&
  457.         fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)
  458.         ) {
  459.         /* Write the path as a rectangle. */
  460.         code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
  461.                       fixed2int_var(box.p.x),
  462.                       fixed2int_var(box.p.y),
  463.                       fixed2int(box.q.x - box.p.x),
  464.                       fixed2int(box.q.y - box.p.y));
  465.         } else if ( !(cldev->disable_mask & clist_disable_complex_clip) ) {
  466.         /* Write the path. */
  467.         code = cmd_put_path(cldev, pcls, &pcpath->path,
  468.                     int2fixed(ymin - 1),
  469.                     int2fixed(ymax + 1),
  470.                     (pcpath->rule == gx_rule_even_odd ?
  471.                      cmd_opv_eofill : cmd_opv_fill),
  472.                     true, sn_not_first);
  473.         } else {
  474.           /* Complex paths disabled: write outer box as clip */
  475.           punt_to_outer_box = true;
  476.         }
  477.     } else {        /* Write out the rectangles. */
  478.         const gx_clip_list *list = gx_cpath_list(pcpath);
  479.         const gx_clip_rect *prect = list->head;
  480.  
  481.         if (prect == 0)
  482.         prect = &list->single;
  483.         else if (cldev->disable_mask & clist_disable_complex_clip)
  484.         punt_to_outer_box = true;
  485.         if (!punt_to_outer_box) {
  486.         for (; prect != 0 && code >= 0; prect = prect->next)
  487.             if (prect->xmax > prect->xmin &&
  488.             prect->ymin < ymax && prect->ymax > ymin
  489.             ) {
  490.             code =
  491.                 cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
  492.                            prect->xmin, prect->ymin,
  493.                            prect->xmax - prect->xmin,
  494.                        prect->ymax - prect->ymin);
  495.             }
  496.         }
  497.     }
  498.     if (punt_to_outer_box) {
  499.         /* Clip is complex, but disabled. Write out the outer box */
  500.         gs_fixed_rect box;
  501.  
  502.         gx_cpath_outer_box(pcpath, &box);
  503.         box.p.x = fixed_floor(box.p.x);
  504.         box.p.y = fixed_floor(box.p.y);
  505.         code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
  506.                       fixed2int_var(box.p.x),
  507.                       fixed2int_var(box.p.y),
  508.                       fixed2int_ceiling(box.q.x - box.p.x),
  509.                       fixed2int_ceiling(box.q.y - box.p.y));
  510.     }
  511.     {
  512.         int end_code =
  513.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 1);
  514.  
  515.         if (code >= 0)
  516.         code = end_code;    /* take the first failure seen */
  517.         if (end_code < 0 && cldev->error_is_retryable) {
  518.         /*
  519.          * end_clip has to work despite lo-mem to maintain consistency.
  520.          * This isn't error recovery, but just to prevent dangling
  521.          * cmd_opv_begin_clip's.
  522.          */
  523.             ++cldev->ignore_lo_mem_warnings;
  524.             end_code =
  525.             set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 1);
  526.             --cldev->ignore_lo_mem_warnings;
  527.         }
  528.     }
  529.     if (code < 0)
  530.         return code;
  531.     pcls->clip_enabled = 1;
  532.     pcls->known |= clip_path_known;
  533.     }
  534.     if (unknown & color_space_known) {
  535.     byte *dp;
  536.  
  537.     if (cldev->color_space.byte1 & 8) {    /* indexed */
  538.         const gs_color_space *pcs = cldev->color_space.space;
  539.         int hival = pcs->params.indexed.hival;
  540.         uint num_values = (hival + 1) *
  541.         gs_color_space_num_components(
  542.             (const gs_color_space *)&pcs->params.indexed.base_space);
  543.         bool use_proc = cldev->color_space.byte1 & 4;
  544.         const void *map_data;
  545.         uint map_size;
  546.  
  547.         if (use_proc) {
  548.         map_data = pcs->params.indexed.lookup.map->values;
  549.         map_size = num_values *
  550.             sizeof(pcs->params.indexed.lookup.map->values[0]);
  551.         } else {
  552.         map_data = pcs->params.indexed.lookup.table.data;
  553.         map_size = num_values;
  554.         }
  555.         code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space,
  556.                   2 + cmd_sizew(hival) + map_size);
  557.         if (code < 0)
  558.         return code;
  559.         memcpy(cmd_put_w(hival, dp + 2), map_data, map_size);
  560.     } else {
  561.         code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space, 2);
  562.         if (code < 0)
  563.         return code;
  564.     }
  565.     dp[1] = cldev->color_space.byte1;
  566.     pcls->known |= color_space_known;
  567.     }
  568.     /****** HANDLE masks ******/
  569.     return 0;
  570. }
  571.  
  572. /* ------ Driver procedures ------ */
  573.  
  574. int
  575. clist_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
  576.         const gx_fill_params * params, const gx_drawing_color * pdcolor,
  577.         const gx_clip_path * pcpath)
  578. {
  579.     gx_device_clist_writer * const cdev =
  580.     &((gx_device_clist *)dev)->writer;
  581.     uint unknown = 0;
  582.     int y, height, y0, y1;
  583.     gs_logical_operation_t lop = pis->log_op;
  584.     byte op = (byte)
  585.     (params->rule == gx_rule_even_odd ?
  586.      cmd_opv_eofill : cmd_opv_fill);
  587.     gs_fixed_point adjust;
  588.     bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
  589.  
  590.     if ( (cdev->disable_mask & clist_disable_fill_path) ||
  591.      gs_debug_c(',')
  592.      ) {
  593.     /* Disable path-based banding. */
  594.     return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
  595.                     pcpath);
  596.     }
  597.     adjust = params->adjust;
  598.     {
  599.     gs_fixed_rect bbox;
  600.  
  601.     gx_path_bbox(ppath, &bbox);
  602.     y = fixed2int(bbox.p.y) - 1;
  603.     height = fixed2int_ceiling(bbox.q.y) - y + 1;
  604.     fit_fill_y(dev, y, height);
  605.     fit_fill_h(dev, y, height);
  606.     if (height <= 0)
  607.         return 0;
  608.     }
  609.     y0 = y;
  610.     y1 = y + height;
  611.     cmd_check_fill_known(cdev, pis, params->flatness, &adjust, pcpath,
  612.              &unknown);
  613.     if (unknown)
  614.     cmd_clear_known(cdev, unknown);
  615.     FOR_RECTS_NO_ERROR {
  616.     int code = cmd_do_write_unknown(cdev, pcls, FILL_KNOWN);
  617.  
  618.     if (code < 0)
  619.         return code;
  620.     if ((code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
  621.         (code = cmd_update_lop(cdev, pcls, lop)) < 0
  622.         )
  623.         return code;
  624.     code = cmd_put_drawing_color(cdev, pcls, pdcolor);
  625.     if (code < 0) {
  626.         /* Something went wrong, use the default implementation. */
  627.         return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
  628.                     pcpath);
  629.     }
  630.     pcls->colors_used.slow_rop |= slow_rop;
  631.     code = cmd_put_path(cdev, pcls, ppath,
  632.                 int2fixed(max(y - 1, y0)),
  633.                 int2fixed(min(y + height + 1, y1)),
  634.                 op + code,    /* cmd_dc_type */
  635.                 true, sn_none /* fill doesn't need the notes */ );
  636.     if (code < 0)
  637.         return code;
  638.     } END_RECTS_NO_ERROR;
  639.     return 0;
  640. }
  641.  
  642. int
  643. clist_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
  644.           const gx_stroke_params * params,
  645.           const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
  646. {
  647.     gx_device_clist_writer * const cdev =
  648.     &((gx_device_clist *)dev)->writer;
  649.     int pattern_size = pis->line_params.dash.pattern_size;
  650.     uint unknown = 0;
  651.     gs_fixed_rect bbox;
  652.     gs_fixed_point expansion;
  653.     int adjust_y;
  654.     int y, height, y0, y1;
  655.     gs_logical_operation_t lop = pis->log_op;
  656.     bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
  657.  
  658.     if ((cdev->disable_mask & clist_disable_stroke_path) ||
  659.     gs_debug_c(',')
  660.     ) {
  661.     /* Disable path-based banding. */
  662.     return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  663.                       pcpath);
  664.     }
  665.     gx_path_bbox(ppath, &bbox);
  666.     /* We must use the supplied imager state, not our saved one, */
  667.     /* for computing the stroke expansion. */
  668.     if (gx_stroke_path_expansion(pis, ppath, &expansion) < 0) {
  669.     /* Expansion is too large: use the entire page. */
  670.     adjust_y = 0;
  671.     y = 0;
  672.     height = dev->height;
  673.     } else {
  674.     adjust_y = fixed2int_ceiling(expansion.y) + 1;
  675.     y = fixed2int(bbox.p.y) - adjust_y;
  676.     height = fixed2int_ceiling(bbox.q.y) - y + adjust_y;
  677.     fit_fill_y(dev, y, height);
  678.     fit_fill_h(dev, y, height);
  679.     if (height <= 0)
  680.         return 0;
  681.     }
  682.     y0 = y;
  683.     y1 = y + height;
  684.     /* Check the dash pattern, since we bail out if */
  685.     /* the pattern is too large. */
  686.     if (cdev->imager_state.line_params.dash.pattern_size != pattern_size ||
  687.     (pattern_size != 0 &&
  688.      memcmp(cdev->dash_pattern, pis->line_params.dash.pattern,
  689.         pattern_size * sizeof(float))) ||
  690.     cdev->imager_state.line_params.dash.offset !=
  691.       pis->line_params.dash.offset ||
  692.     cdev->imager_state.line_params.dash.adapt !=
  693.       pis->line_params.dash.adapt ||
  694.     cdev->imager_state.line_params.dot_length !=
  695.       pis->line_params.dot_length ||
  696.     cdev->imager_state.line_params.dot_length_absolute !=
  697.       pis->line_params.dot_length_absolute
  698.     ) {
  699.     /* Bail out if the dash pattern is too long. */
  700.     if (pattern_size > cmd_max_dash)
  701.         return gx_default_stroke_path(dev, pis, ppath, params,
  702.                       pdcolor, pcpath);
  703.     unknown |= dash_known;
  704.     /*
  705.      * Temporarily reset the dash pattern pointer for gx_set_dash,
  706.      * but don't leave it set, since that would confuse the GC.
  707.      */
  708.     cdev->imager_state.line_params.dash.pattern = cdev->dash_pattern;
  709.     gx_set_dash(&cdev->imager_state.line_params.dash,
  710.             pis->line_params.dash.pattern,
  711.             pis->line_params.dash.pattern_size,
  712.             pis->line_params.dash.offset, NULL);
  713.     cdev->imager_state.line_params.dash.pattern = 0;
  714.     gx_set_dash_adapt(&cdev->imager_state.line_params.dash,
  715.               pis->line_params.dash.adapt);
  716.     gx_set_dot_length(&cdev->imager_state.line_params,
  717.               pis->line_params.dot_length,
  718.               pis->line_params.dot_length_absolute);
  719.     }
  720.     if (state_neq(line_params.cap) || state_neq(line_params.join)) {
  721.     unknown |= cap_join_known;
  722.     state_update(line_params.cap);
  723.     state_update(line_params.join);
  724.     }
  725.     cmd_check_fill_known(cdev, pis, params->flatness, &pis->fill_adjust,
  726.              pcpath, &unknown);
  727.     if (state_neq(line_params.half_width)) {
  728.     unknown |= line_width_known;
  729.     state_update(line_params.half_width);
  730.     }
  731.     if (state_neq(line_params.miter_limit)) {
  732.     unknown |= miter_limit_known;
  733.     gx_set_miter_limit(&cdev->imager_state.line_params,
  734.                pis->line_params.miter_limit);
  735.     }
  736.     if (state_neq(ctm.xx) || state_neq(ctm.xy) ||
  737.     state_neq(ctm.yx) || state_neq(ctm.yy) ||
  738.     /* We don't actually need tx or ty, but we don't want to bother */
  739.     /* tracking them separately from the other coefficients. */
  740.     state_neq(ctm.tx) || state_neq(ctm.ty)
  741.     ) {
  742.     unknown |= ctm_known;
  743.     state_update(ctm);
  744.     }
  745.     if (unknown)
  746.     cmd_clear_known(cdev, unknown);
  747.     FOR_RECTS_NO_ERROR {
  748.     int code;
  749.  
  750.     if ((code = cmd_do_write_unknown(cdev, pcls, stroke_all_known)) < 0 ||
  751.         (code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
  752.         (code = cmd_update_lop(cdev, pcls, lop)) < 0
  753.         )
  754.         return code;
  755.     code = cmd_put_drawing_color(cdev, pcls, pdcolor);
  756.     if (code < 0) {
  757.         /* Something went wrong, use the default implementation. */
  758.         return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  759.                       pcpath);
  760.     }
  761.     pcls->colors_used.slow_rop |= slow_rop;
  762.     {
  763.         fixed ymin, ymax;
  764.  
  765.         /*
  766.          * If a dash pattern is active, we can't skip segments
  767.          * outside the clipping region, because that would throw off
  768.          * the pattern.
  769.          */
  770.         if (pattern_size == 0) {
  771.         fixed expand = adjust_y + expansion.y;
  772.  
  773.         ymin = int2fixed(max(y - expand, y0));
  774.         ymax = int2fixed(min(y + height + expand, y1));
  775.         } else {
  776.         ymin = min_fixed;
  777.         ymax = max_fixed;
  778.         }
  779.         code = cmd_put_path(cdev, pcls, ppath, ymin, ymax,
  780.                 cmd_opv_stroke + code,    /* cmd_dc_type */
  781.                 false, (segment_notes)~0);
  782.         if (code < 0)
  783.         return code;
  784.     }
  785.     } END_RECTS_NO_ERROR;
  786.     return 0;
  787. }
  788.  
  789. /*
  790.  * Fill_parallelogram and fill_triangle aren't very efficient.  This isn't
  791.  * important right now, since the non-degenerate case is only used for
  792.  * smooth shading.  However, the rectangular case of fill_parallelogram is
  793.  * sometimes used for images, so its performance does matter.
  794.  */
  795.  
  796. private int
  797. clist_put_polyfill(gx_device *dev, fixed px, fixed py,
  798.            const gs_fixed_point *points, int num_points,
  799.            const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
  800. {
  801.     gx_path path;
  802.     gs_memory_t *mem = dev->memory;
  803.     int code;
  804.     gx_device_clist_writer * const cdev =
  805.     &((gx_device_clist *)dev)->writer;
  806.     gs_fixed_rect bbox;
  807.     int y, height, y0, y1;
  808.     bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
  809.  
  810.     if (gs_debug_c(','))
  811.     return -1;        /* path-based banding is disabled */
  812.     gx_path_init_local(&path, mem);
  813.     if ((code = gx_path_add_point(&path, px, py)) < 0 ||
  814.     (code = gx_path_add_lines(&path, points, num_points)) < 0
  815.     )
  816.     goto out;
  817.     gx_path_bbox(&path, &bbox);
  818.     y = fixed2int(bbox.p.y) - 1;
  819.     height = fixed2int_ceiling(bbox.q.y) - y + 1;
  820.     fit_fill_y(dev, y, height);
  821.     fit_fill_h(dev, y, height);
  822.     if (height <= 0)
  823.     return 0;
  824.     y0 = y;
  825.     y1 = y + height;
  826.     FOR_RECTS_NO_ERROR {
  827.     if ((code = cmd_update_lop(cdev, pcls, lop)) < 0 ||
  828.         (code = cmd_put_drawing_color(cdev, pcls, pdcolor)) < 0)
  829.         goto out;
  830.     pcls->colors_used.slow_rop |= slow_rop;
  831.     code = cmd_put_path(cdev, pcls, &path,
  832.                 int2fixed(max(y - 1, y0)),
  833.                 int2fixed(min(y + height + 1, y1)),
  834.                 cmd_opv_polyfill + code,
  835.                 true, sn_none /* fill doesn't need the notes */ );
  836.     if (code < 0)
  837.         goto out;
  838.     } END_RECTS_NO_ERROR;
  839. out:
  840.     gx_path_free(&path, "clist_put_polyfill");
  841.     return code;
  842. }
  843.  
  844. int
  845. clist_fill_parallelogram(gx_device *dev, fixed px, fixed py,
  846.              fixed ax, fixed ay, fixed bx, fixed by,
  847.              const gx_drawing_color *pdcolor,
  848.              gs_logical_operation_t lop)
  849. {
  850.     gs_fixed_point pts[3];
  851.     int code;
  852.  
  853.     if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) {
  854.     gs_int_rect r;
  855.  
  856.     INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by);
  857.     return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x,
  858.                         r.q.y - r.p.y, pdcolor, dev, lop);
  859.     }
  860.     pts[0].x = px + ax, pts[0].y = py + ay;
  861.     pts[1].x = pts[0].x + bx, pts[1].y = pts[0].y + by;
  862.     pts[2].x = px + bx, pts[2].y = py + by;
  863.     code = clist_put_polyfill(dev, px, py, pts, 3, pdcolor, lop);
  864.     return (code >= 0 ? code :
  865.         gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
  866.                       pdcolor, lop));
  867. }
  868.  
  869. int
  870. clist_fill_triangle(gx_device *dev, fixed px, fixed py,
  871.             fixed ax, fixed ay, fixed bx, fixed by,
  872.             const gx_drawing_color *pdcolor,
  873.             gs_logical_operation_t lop)
  874. {
  875.     gs_fixed_point pts[2];
  876.     int code;
  877.  
  878.     pts[0].x = px + ax, pts[0].y = py + ay;
  879.     pts[1].x = px + bx, pts[1].y = py + by;
  880.     code = clist_put_polyfill(dev, px, py, pts, 2, pdcolor, lop);
  881.     return (code >= 0 ? code :
  882.         gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
  883.                      pdcolor, lop));
  884. }
  885.  
  886. /* ------ Path utilities ------ */
  887.  
  888. /* Define the state bookkeeping for writing path segments. */
  889. typedef struct cmd_segment_writer_s {
  890.     /* Set at initialization */
  891.     gx_device_clist_writer *cldev;
  892.     gx_clist_state *pcls;
  893.     /* Updated dynamically */
  894.     segment_notes notes;
  895.     byte *dp;
  896.     int len;
  897.     gs_fixed_point delta_first;
  898.     byte cmd[6 * (1 + sizeof(fixed))];
  899. }
  900. cmd_segment_writer;
  901.  
  902. /* Put out a path segment command. */
  903. private int
  904. cmd_put_segment(cmd_segment_writer * psw, byte op,
  905.         const fixed * operands, segment_notes notes)
  906. {
  907.     const fixed *optr = operands;
  908.     /* Fetch num_operands before possible command merging. */
  909.     static const byte op_num_operands[] = {
  910.     cmd_segment_op_num_operands_values
  911.     };
  912.     int i = op_num_operands[op & 0xf];
  913.     /* One picky compiler complains if we initialize to psw->cmd - 1. */
  914.     byte *q = psw->cmd;
  915.  
  916.     --q;
  917.  
  918. #ifdef DEBUG
  919.     if (gs_debug_c('L')) {
  920.     int j;
  921.  
  922.     dlprintf2("[L]  %s:%d:", cmd_sub_op_names[op >> 4][op & 0xf],
  923.           (int)notes);
  924.     for (j = 0; j < i; ++j)
  925.         dprintf1(" %g", fixed2float(operands[j]));
  926.     dputs("\n");
  927.     }
  928. #endif
  929.  
  930.     /* Merge or shorten commands if possible. */
  931.     if (op == cmd_opv_rlineto) {
  932.     if (operands[0] == 0)
  933.         op = cmd_opv_vlineto, optr = ++operands, i = 1;
  934.     else if (operands[1] == 0)
  935.         op = cmd_opv_hlineto, i = 1;
  936.     else
  937.         switch (*psw->dp) {
  938.         case cmd_opv_rmoveto:
  939.             psw->delta_first.x = operands[0];
  940.             psw->delta_first.y = operands[1];
  941.             op = cmd_opv_rmlineto;
  942.           merge:cmd_uncount_op(*psw->dp, psw->len);
  943.             cmd_shorten_op(psw->cldev, psw->pcls, psw->len);    /* delete it */
  944.             q += psw->len - 1;
  945.             break;
  946.         case cmd_opv_rmlineto:
  947.             if (notes != psw->notes)
  948.             break;
  949.             op = cmd_opv_rm2lineto;
  950.             goto merge;
  951.         case cmd_opv_rm2lineto:
  952.             if (notes != psw->notes)
  953.             break;
  954.             if (operands[0] == -psw->delta_first.x &&
  955.             operands[1] == -psw->delta_first.y
  956.             ) {
  957.             cmd_uncount_op(cmd_opv_rm2lineto, psw->len);
  958.             *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len);
  959.             return 0;
  960.             }
  961.             break;
  962.         default:
  963.             ;
  964.         }
  965.     }
  966.     for (; --i >= 0; ++optr) {
  967.     fixed d = *optr, d2;
  968.  
  969.     if (is_bits(d, _fixed_shift + 11) &&
  970.         !(d & (float2fixed(0.25) - 1))
  971.         ) {
  972.         cmd_count_add1(stats_cmd_diffs[3]);
  973.         d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000;
  974.         q += 2;
  975.     } else if (is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19)) {
  976.         cmd_count_add1(stats_cmd_diffs[0]);
  977.         q[1] = (byte) ((d >> 13) & 0x3f);
  978.         q[2] = (byte) (d >> 5);
  979.         q[3] = (byte) ((d << 3) + ((d2 >> 16) & 7));
  980.         q[4] = (byte) (d2 >> 8);
  981.         q[5] = (byte) d2;
  982.         q += 5;
  983.         --i, ++optr;
  984.         continue;
  985.     } else if (is_bits(d, 22)) {
  986.         cmd_count_add1(stats_cmd_diffs[1]);
  987.         q[1] = (byte) (((d >> 16) & 0x3f) + 0x40);
  988.         q += 3;
  989.     } else if (is_bits(d, 30)) {
  990.         cmd_count_add1(stats_cmd_diffs[2]);
  991.         q[1] = (byte) (((d >> 24) & 0x3f) + 0x80);
  992.         q[2] = (byte) (d >> 16);
  993.         q += 4;
  994.     } else {
  995.         int b;
  996.  
  997.         cmd_count_add1(stats_cmd_diffs[4]);
  998.         *++q = 0xe0;
  999.         for (b = sizeof(fixed) - 1; b > 1; --b)
  1000.         *++q = (byte) (d >> (b * 8));
  1001.         q += 2;
  1002.     }
  1003.     q[-1] = (byte) (d >> 8);
  1004.     *q = (byte) d;
  1005.     }
  1006.     if (notes != psw->notes) {
  1007.     byte *dp;
  1008.     int code =
  1009.         set_cmd_put_op(dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 3);
  1010.  
  1011.     if (code < 0)
  1012.         return code;
  1013.     dp[1] = segment_notes_known;
  1014.     dp[2] = notes;
  1015.     psw->notes = notes;
  1016.     } {
  1017.     int len = q + 2 - psw->cmd;
  1018.     byte *dp;
  1019.     int code = set_cmd_put_op(dp, psw->cldev, psw->pcls, op, len);
  1020.  
  1021.     if (code < 0)
  1022.         return code;
  1023.     memcpy(dp + 1, psw->cmd, len - 1);
  1024.     psw->len = len;
  1025.     psw->dp = dp;
  1026.     }
  1027.     return 0;
  1028. }
  1029. /* Put out a line segment command. */
  1030. #define cmd_put_rmoveto(psw, operands)\
  1031.   cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none)
  1032. #define cmd_put_rlineto(psw, operands, notes)\
  1033.   cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
  1034.  
  1035. /*
  1036.  * Write a path.  We go to a lot of trouble to omit segments that are
  1037.  * entirely outside the band.
  1038.  */
  1039. private int
  1040. cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
  1041.          const gx_path * ppath, fixed ymin, fixed ymax, byte path_op,
  1042.          bool implicit_close, segment_notes keep_notes)
  1043. {
  1044.     gs_path_enum cenum;
  1045.     cmd_segment_writer writer;
  1046.  
  1047.     /*
  1048.      * initial_op is logically const.  We would like to declare it as
  1049.      * static const, since some systems really dislike non-const statics,
  1050.      * but this would entail a cast in set_first_point() that provokes a
  1051.      * warning message from gcc.  Instead, we pay the (tiny) cost of an
  1052.      * unnecessary dynamic initialization.
  1053.      */
  1054.     byte initial_op = cmd_opv_end_run;
  1055.  
  1056.     /*
  1057.      * We define the 'side' of a point according to its Y value as
  1058.      * follows:
  1059.      */
  1060. #define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0)
  1061.  
  1062.     /*
  1063.      * While writing a subpath, we need to keep track of any segments
  1064.      * skipped at the beginning of the subpath and any segments skipped
  1065.      * just before the current segment.  We do this with two sets of
  1066.      * state variables, one that tracks the actual path segments and one
  1067.      * that tracks the emitted segments.
  1068.      *
  1069.      * The following track the actual segments:
  1070.      */
  1071.  
  1072.     /*
  1073.      * The point and side of the last moveto (skipped if
  1074.      * start_side != 0):
  1075.      */
  1076.     gs_fixed_point start;
  1077.     int start_side;
  1078.  
  1079.     /*
  1080.      * Whether any lines or curves were skipped immediately
  1081.      * following the moveto:
  1082.      */
  1083.     bool start_skip;
  1084.  
  1085.     /* The side of the last point: */
  1086.     int side;
  1087.  
  1088.     /* The last point with side != 0: */
  1089.     gs_fixed_point out;
  1090.  
  1091.     /* If the last out-going segment was a lineto, */
  1092.     /* its notes: */
  1093.     segment_notes out_notes;
  1094.  
  1095.     /*
  1096.      * The following track the emitted segments:
  1097.      */
  1098.  
  1099.     /* The last point emitted: */
  1100.     fixed px = int2fixed(pcls->rect.x);
  1101.     fixed py = int2fixed(pcls->rect.y);
  1102.  
  1103.     /* The point of the last emitted moveto: */
  1104.     gs_fixed_point first;
  1105.  
  1106.     /* Information about the last emitted operation: */
  1107.     int open = 0;        /* -1 if last was moveto, 1 if line/curveto, */
  1108.  
  1109.     /* 0 if newpath/closepath */
  1110.  
  1111.  
  1112.     if_debug4('p', "[p]initial (%g,%g), clip [%g..%g)\n",
  1113.           fixed2float(px), fixed2float(py),
  1114.           fixed2float(ymin), fixed2float(ymax));
  1115.     gx_path_enum_init(&cenum, ppath);
  1116.     writer.cldev = cldev;
  1117.     writer.pcls = pcls;
  1118.     writer.notes = sn_none;
  1119. #define set_first_point() (writer.dp = &initial_op)
  1120. #define first_point() (writer.dp == &initial_op)
  1121.     set_first_point();
  1122.     for (;;) {
  1123.     fixed vs[6];
  1124.     struct { fixed vs[6]; } prev;
  1125.  
  1126. #define A vs[0]
  1127. #define B vs[1]
  1128. #define C vs[2]
  1129. #define D vs[3]
  1130. #define E vs[4]
  1131. #define F vs[5]
  1132.     int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
  1133.     byte *dp;
  1134.     int code;
  1135.  
  1136.     switch (pe_op) {
  1137.         case 0:
  1138.         /* If the path is open and needs an implicit close, */
  1139.         /* do the close and then come here again. */
  1140.         if (open > 0 && implicit_close)
  1141.             goto close;
  1142.         /* All done. */
  1143.         pcls->rect.x = fixed2int_var(px);
  1144.         pcls->rect.y = fixed2int_var(py);
  1145.         if_debug2('p', "[p]final (%d,%d)\n",
  1146.               pcls->rect.x, pcls->rect.y);
  1147.         return set_cmd_put_op(dp, cldev, pcls, path_op, 1);
  1148.         case gs_pe_moveto:
  1149.         /* If the path is open and needs an implicit close, */
  1150.         /* do a closepath and then redo the moveto. */
  1151.         if (open > 0 && implicit_close) {
  1152.             gx_path_enum_backup(&cenum);
  1153.             goto close;
  1154.         }
  1155.         open = -1;
  1156.         start.x = A, start.y = B;
  1157.         start_skip = false;
  1158.         if ((start_side = side = which_side(B)) != 0) {
  1159.             out.x = A, out.y = B;
  1160.             if_debug3('p', "[p]skip moveto (%g,%g) side %d\n",
  1161.                   fixed2float(out.x), fixed2float(out.y),
  1162.                   side);
  1163.             continue;
  1164.         }
  1165.         C = A - px, D = B - py;
  1166.         first.x = px = A, first.y = py = B;
  1167.         code = cmd_put_rmoveto(&writer, &C);
  1168.         if_debug2('p', "[p]moveto (%g,%g)\n",
  1169.               fixed2float(px), fixed2float(py));
  1170.         break;
  1171.         case gs_pe_lineto:
  1172.         {
  1173.             int next_side = which_side(B);
  1174.             segment_notes notes =
  1175.             gx_path_enum_notes(&cenum) & keep_notes;
  1176.  
  1177.             if (next_side == side && side != 0) {    /* Skip a line completely outside the clip region. */
  1178.             if (open < 0)
  1179.                 start_skip = true;
  1180.             out.x = A, out.y = B;
  1181.             out_notes = notes;
  1182.             if_debug3('p', "[p]skip lineto (%g,%g) side %d\n",
  1183.                   fixed2float(out.x), fixed2float(out.y),
  1184.                   side);
  1185.             continue;
  1186.             }
  1187.             /* If we skipped any segments, put out a moveto/lineto. */
  1188.             if (side && (px != out.x || py != out.y || first_point())) {
  1189.             C = out.x - px, D = out.y - py;
  1190.             if (open < 0) {
  1191.                 first = out;
  1192.                 code = cmd_put_rmoveto(&writer, &C);
  1193.             } else
  1194.                 code = cmd_put_rlineto(&writer, &C, out_notes);
  1195.             if (code < 0)
  1196.                 return code;
  1197.             px = out.x, py = out.y;
  1198.             if_debug3('p', "[p]catchup %s (%g,%g) for line\n",
  1199.                   (open < 0 ? "moveto" : "lineto"),
  1200.                   fixed2float(px), fixed2float(py));
  1201.             }
  1202.             if ((side = next_side) != 0) {    /* Note a vertex going outside the clip region. */
  1203.             out.x = A, out.y = B;
  1204.             }
  1205.             C = A - px, D = B - py;
  1206.             px = A, py = B;
  1207.             open = 1;
  1208.             code = cmd_put_rlineto(&writer, &C, notes);
  1209.         }
  1210.         if_debug3('p', "[p]lineto (%g,%g) side %d\n",
  1211.               fixed2float(px), fixed2float(py), side);
  1212.         break;
  1213.         case gs_pe_closepath:
  1214. #ifdef DEBUG
  1215.         {
  1216.             gs_path_enum cpenum;
  1217.             gs_fixed_point cvs[3];
  1218.             int op;
  1219.  
  1220.             cpenum = cenum;
  1221.             switch (op = gx_path_enum_next(&cpenum, cvs)) {
  1222.             case 0:
  1223.             case gs_pe_moveto:
  1224.                 break;
  1225.             default:
  1226.                 lprintf1("closepath followed by %d, not end/moveto!\n",
  1227.                      op);
  1228.             }
  1229.         }
  1230. #endif
  1231.         /* A closepath may require drawing an explicit line if */
  1232.         /* we skipped any segments at the beginning of the path. */
  1233.           close:if (side != start_side) {    /* If we skipped any segments, put out a moveto/lineto. */
  1234.             if (side && (px != out.x || py != out.y || first_point())) {
  1235.             C = out.x - px, D = out.y - py;
  1236.             code = cmd_put_rlineto(&writer, &C, out_notes);
  1237.             if (code < 0)
  1238.                 return code;
  1239.             px = out.x, py = out.y;
  1240.             if_debug2('p', "[p]catchup line (%g,%g) for close\n",
  1241.                   fixed2float(px), fixed2float(py));
  1242.             }
  1243.             if (open > 0 && start_skip) {    /* Draw the closing line back to the start. */
  1244.             C = start.x - px, D = start.y - py;
  1245.             code = cmd_put_rlineto(&writer, &C, sn_none);
  1246.             if (code < 0)
  1247.                 return code;
  1248.             px = start.x, py = start.y;
  1249.             if_debug2('p', "[p]draw close to (%g,%g)\n",
  1250.                   fixed2float(px), fixed2float(py));
  1251.             }
  1252.         }
  1253.         /*
  1254.          * We don't bother to update side because we know that the
  1255.          * next element after a closepath, if any, must be a moveto.
  1256.          * We must handle explicitly the possibility that the entire
  1257.          * subpath was skipped.
  1258.          */
  1259.         if (implicit_close || open <= 0) {
  1260.             open = 0;
  1261.             /*
  1262.              * Force writing an explicit moveto if the next subpath
  1263.              * starts with a moveto to the same point where this one
  1264.              * ends.
  1265.              */
  1266.             set_first_point();
  1267.             continue;
  1268.         }
  1269.         open = 0;
  1270.         px = first.x, py = first.y;
  1271.         code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none);
  1272.         if_debug0('p', "[p]close\n");
  1273.         break;
  1274.         case gs_pe_curveto:
  1275.         {
  1276.             segment_notes notes =
  1277.             gx_path_enum_notes(&cenum) & keep_notes;
  1278.  
  1279.             {
  1280.             fixed bpy, bqy;
  1281.             int all_side, out_side;
  1282.  
  1283.             /* Compute the Y bounds for the clipping check. */
  1284.             if (B < D)
  1285.                 bpy = B, bqy = D;
  1286.             else
  1287.                 bpy = D, bqy = B;
  1288.             if (F < bpy)
  1289.                 bpy = F;
  1290.             else if (F > bqy)
  1291.                 bqy = F;
  1292.             all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0);
  1293.             if (all_side != 0) {
  1294.                 if (all_side == side) {    /* Skip a curve entirely outside the clip region. */
  1295.                 if (open < 0)
  1296.                     start_skip = true;
  1297.                 out.x = E, out.y = F;
  1298.                 out_notes = notes;
  1299.                 if_debug3('p', "[p]skip curveto (%g,%g) side %d\n",
  1300.                      fixed2float(out.x), fixed2float(out.y),
  1301.                       side);
  1302.                 continue;
  1303.                 }
  1304.                 out_side = all_side;
  1305.             } else
  1306.                 out_side = which_side(F);
  1307.             /* If we skipped any segments, put out a moveto/lineto. */
  1308.             if (side && (px != out.x || py != out.y || first_point())) {
  1309.                 fixed diff[2];
  1310.  
  1311.                 diff[0] = out.x - px, diff[1] = out.y - py;
  1312.                 if (open < 0) {
  1313.                 first = out;
  1314.                 code = cmd_put_rmoveto(&writer, diff);
  1315.                 } else
  1316.                 code = cmd_put_rlineto(&writer, diff, out_notes);
  1317.                 if (code < 0)
  1318.                 return code;
  1319.                 px = out.x, py = out.y;
  1320.                 if_debug3('p', "[p]catchup %s (%g,%g) for curve\n",
  1321.                       (open < 0 ? "moveto" : "lineto"),
  1322.                       fixed2float(px), fixed2float(py));
  1323.             }
  1324.             if ((side = out_side) != 0) {    /* Note a vertex going outside the clip region. */
  1325.                 out.x = E, out.y = F;
  1326.             }
  1327.             }
  1328.             {
  1329.             fixed nx = E, ny = F;
  1330.             const fixed *optr = vs;
  1331.             byte op;
  1332.  
  1333.             if_debug7('p', "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n",
  1334.                   fixed2float(A), fixed2float(B),
  1335.                   fixed2float(C), fixed2float(D),
  1336.                   fixed2float(E), fixed2float(F), side);
  1337.             E -= C, F -= D;
  1338.             C -= A, D -= B;
  1339.             A -= px, B -= py;
  1340.             if (*writer.dp >= cmd_opv_min_curveto &&
  1341.                 *writer.dp <= cmd_opv_max_curveto &&
  1342.                 ((prev.A == 0 &&
  1343.                   A == prev.E && C == prev.C && E == prev.A &&
  1344.                   B == -prev.F && D == -prev.D && F == -prev.B) ||
  1345.                  (prev.A != 0 &&
  1346.                   A == -prev.E && C == -prev.C && E == -prev.A &&
  1347.                   B == prev.F && D == prev.D && F == prev.B))
  1348.                 )
  1349.                 op = cmd_opv_scurveto;
  1350.             else if (B == 0 && E == 0) {
  1351.                 B = A, E = F, optr++, op = cmd_opv_hvcurveto;
  1352.                 if ((B ^ D) >= 0) {
  1353.                 if (C == D && E == B)
  1354.                     op = cmd_opv_hqcurveto;
  1355.                 } else if (C == -D && E == -B)
  1356.                 C = D, op = cmd_opv_hqcurveto;
  1357.             } else if (A == 0 && F == 0) {
  1358.                 optr++, op = cmd_opv_vhcurveto;
  1359.                 if ((B ^ C) >= 0) {
  1360.                 if (D == C && E == B)
  1361.                     op = cmd_opv_vqcurveto;
  1362.                 } else if (D == -C && E == -B)
  1363.                 op = cmd_opv_vqcurveto;
  1364.             } else if (A == 0 && B == 0)
  1365.                 optr += 2, op = cmd_opv_nrcurveto;
  1366.             else if (E == 0 && F == 0)
  1367.                 op = cmd_opv_rncurveto;
  1368.             else
  1369.                 op = cmd_opv_rrcurveto;
  1370.             memcpy(prev.vs, vs, sizeof(prev.vs));
  1371.             px = nx, py = ny;
  1372.             open = 1;
  1373.             code = cmd_put_segment(&writer, op, optr, notes);
  1374.             }
  1375.         }
  1376.         break;
  1377.         default:
  1378.         return_error(gs_error_rangecheck);
  1379.     }
  1380.     if (code < 0)
  1381.         return code;
  1382. #undef A
  1383. #undef B
  1384. #undef C
  1385. #undef D
  1386. #undef E
  1387. #undef F
  1388.     }
  1389. }
  1390.